{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Siamese Address Similarity with TensorFlow\n",
    "--------------------------\n",
    "\n",
    "Here, we show how to perform address matching with a Siamese RNN model.\n",
    "\n",
    "We start by loading the necessary libraries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/lib/python3.6/importlib/_bootstrap.py:219: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88\n",
      "  return f(*args, **kwds)\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import random\n",
    "import string\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow as tf\n",
    "from tensorflow.python.framework import ops\n",
    "ops.reset_default_graph()\n",
    "\n",
    "model = __import__('siamese_similarity_model')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start a graph session"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "sess = tf.Session()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Set the model parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "batch_size = 200     # How many addresses to train on in one batch\n",
    "n_batches = 300      # How many batches to train on\n",
    "max_address_len = 20 # How many character to crop/pad each address\n",
    "margin = 0.25        # A sort of regularization parameter that allows for 'wiggle' room in bad predicted similarities.\n",
    "num_features = 50    # RNN feature size\n",
    "dropout_keep_prob = 0.8 # Dropout probability"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We need a function to randomly create one typo in a string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_typo(s):\n",
    "    rand_ind = random.choice(range(len(s)))\n",
    "    s_list = list(s)\n",
    "    s_list[rand_ind]=random.choice(string.ascii_lowercase + '0123456789')\n",
    "    s = ''.join(s_list)\n",
    "    return(s)\n",
    "\n",
    "# Generate data\n",
    "street_names = ['abbey', 'baker', 'canal', 'donner', 'elm', 'fifth',\n",
    "                'grandvia', 'hollywood', 'interstate', 'jay', 'kings']\n",
    "street_types = ['rd', 'st', 'ln', 'pass', 'ave', 'hwy', 'cir', 'dr', 'jct']\n",
    "\n",
    "# Define test addresses\n",
    "test_queries = ['111 abbey ln', '271 doner cicle',\n",
    "                '314 king avenue', 'tensorflow is fun']\n",
    "test_references = ['123 abbey ln', '217 donner cir', '314 kings ave',\n",
    "                   '404 hollywood st', 'tensorflow is so fun']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get a batch of size n, half of which is similar addresses, half are not"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_batch(n):\n",
    "    # Generate a list of reference addresses with similar addresses that have\n",
    "    # a typo.\n",
    "    numbers = [random.randint(1, 9999) for i in range(n)]\n",
    "    streets = [random.choice(street_names) for i in range(n)]\n",
    "    street_suffs = [random.choice(street_types) for i in range(n)]\n",
    "    full_streets = [str(w) + ' ' + x + ' ' + y for w,x,y in zip(numbers, streets, street_suffs)]\n",
    "    typo_streets = [create_typo(x) for x in full_streets]\n",
    "    reference = [list(x) for x in zip(full_streets, typo_streets)]\n",
    "    \n",
    "    # Shuffle last half of them for training on dissimilar addresses\n",
    "    half_ix = int(n/2)\n",
    "    bottom_half = reference[half_ix:]\n",
    "    true_address = [x[0] for x in bottom_half]\n",
    "    typo_address = [x[1] for x in bottom_half]\n",
    "    typo_address = list(np.roll(typo_address, 1))\n",
    "    bottom_half = [[x,y] for x,y in zip(true_address, typo_address)]\n",
    "    reference[half_ix:] = bottom_half\n",
    "    \n",
    "    # Get target similarities (1's for similar, -1's for non-similar)\n",
    "    target = [1]*(n-half_ix) + [-1]*half_ix\n",
    "    reference = [[x,y] for x,y in zip(reference, target)]\n",
    "    return reference"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define vocabulary dictionary (remember to save '0' for padding)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "vocab_chars = string.ascii_lowercase + '0123456789 '\n",
    "vocab2ix_dict = {char:(ix+1) for ix, char in enumerate(vocab_chars)}\n",
    "vocab_length = len(vocab_chars) + 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Define vocab one-hot encoding.  Here we get the actual indices for usage in the embedding lookup."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def address2onehot(address,\n",
    "                   vocab2ix_dict = vocab2ix_dict,\n",
    "                   max_address_len = max_address_len):\n",
    "    # translate address string into indices\n",
    "    address_ix = [vocab2ix_dict[x] for x in list(address)]\n",
    "\n",
    "    # Pad or crop to max_address_len\n",
    "    address_ix = (address_ix + [0]*max_address_len)[0:max_address_len]\n",
    "    return address_ix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we define model placeholders."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "address1_ph = tf.placeholder(tf.int32, [None, max_address_len], name=\"address1_ph\")\n",
    "address2_ph = tf.placeholder(tf.int32, [None, max_address_len], name=\"address2_ph\")\n",
    "\n",
    "y_target_ph = tf.placeholder(tf.int32, [None], name=\"y_target_ph\")\n",
    "dropout_keep_prob_ph = tf.placeholder(tf.float32, name=\"dropout_keep_prob\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create embedding lookup. Here we use the identidy matrix so that we have a one-hot encoded lookup."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "identity_mat = tf.diag(tf.ones(shape=[vocab_length]))\n",
    "address1_embed = tf.nn.embedding_lookup(identity_mat, address1_ph)\n",
    "address2_embed = tf.nn.embedding_lookup(identity_mat, address2_ph)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we define the model.  Please see the `06_siamese_similarity_model.py` for details."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define Model\n",
    "text_snn = model.snn(address1_embed, address2_embed, dropout_keep_prob_ph,\n",
    "                     vocab_length, num_features, max_address_len)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can define our accuracy, loss, and prediction functions.  These come from the `06_siamese_similarity_model.py` model function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define Accuracy\n",
    "batch_accuracy = model.accuracy(text_snn, y_target_ph)\n",
    "# Define Loss\n",
    "batch_loss = model.loss(text_snn, y_target_ph, margin)\n",
    "# Define Predictions\n",
    "predictions = model.get_predictions(text_snn)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We declare our optimizer, training operation, and variable initialization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Declare optimizer\n",
    "optimizer = tf.train.AdamOptimizer(0.01)\n",
    "# Apply gradients\n",
    "train_op = optimizer.minimize(batch_loss)\n",
    "\n",
    "# Initialize Variables\n",
    "init = tf.global_variables_initializer()\n",
    "sess.run(init)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we loop through our training iterations and print out convergence statistics every 10 generations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training Metrics, Batch 0: Loss=0.618, Accuracy=0.500.\n",
      "Training Metrics, Batch 10: Loss=0.098, Accuracy=0.685.\n",
      "Training Metrics, Batch 20: Loss=0.058, Accuracy=0.730.\n",
      "Training Metrics, Batch 30: Loss=0.002, Accuracy=0.740.\n",
      "Training Metrics, Batch 40: Loss=0.080, Accuracy=0.720.\n",
      "Training Metrics, Batch 50: Loss=0.011, Accuracy=0.750.\n",
      "Training Metrics, Batch 60: Loss=0.017, Accuracy=0.770.\n",
      "Training Metrics, Batch 70: Loss=-0.006, Accuracy=0.755.\n",
      "Training Metrics, Batch 80: Loss=-0.008, Accuracy=0.745.\n",
      "Training Metrics, Batch 90: Loss=-0.003, Accuracy=0.800.\n",
      "Training Metrics, Batch 100: Loss=0.006, Accuracy=0.780.\n",
      "Training Metrics, Batch 110: Loss=0.025, Accuracy=0.765.\n",
      "Training Metrics, Batch 120: Loss=0.023, Accuracy=0.745.\n",
      "Training Metrics, Batch 130: Loss=-0.012, Accuracy=0.730.\n",
      "Training Metrics, Batch 140: Loss=0.012, Accuracy=0.770.\n",
      "Training Metrics, Batch 150: Loss=0.014, Accuracy=0.710.\n",
      "Training Metrics, Batch 160: Loss=0.003, Accuracy=0.765.\n",
      "Training Metrics, Batch 170: Loss=0.020, Accuracy=0.755.\n",
      "Training Metrics, Batch 180: Loss=0.023, Accuracy=0.750.\n",
      "Training Metrics, Batch 190: Loss=-0.001, Accuracy=0.720.\n",
      "Training Metrics, Batch 200: Loss=-0.013, Accuracy=0.790.\n",
      "Training Metrics, Batch 210: Loss=0.014, Accuracy=0.740.\n",
      "Training Metrics, Batch 220: Loss=-0.015, Accuracy=0.800.\n",
      "Training Metrics, Batch 230: Loss=-0.011, Accuracy=0.800.\n",
      "Training Metrics, Batch 240: Loss=-0.006, Accuracy=0.770.\n",
      "Training Metrics, Batch 250: Loss=-0.032, Accuracy=0.775.\n",
      "Training Metrics, Batch 260: Loss=0.008, Accuracy=0.765.\n",
      "Training Metrics, Batch 270: Loss=-0.013, Accuracy=0.810.\n",
      "Training Metrics, Batch 280: Loss=-0.015, Accuracy=0.750.\n",
      "Training Metrics, Batch 290: Loss=0.010, Accuracy=0.750.\n"
     ]
    }
   ],
   "source": [
    "# Train loop\n",
    "train_loss_vec = []\n",
    "train_acc_vec = []\n",
    "for b in range(n_batches):\n",
    "    # Get a batch of data\n",
    "    batch_data = get_batch(batch_size)\n",
    "    # Shuffle data\n",
    "    np.random.shuffle(batch_data)\n",
    "    # Parse addresses and targets\n",
    "    input_addresses = [x[0] for x in batch_data]\n",
    "    target_similarity = np.array([x[1] for x in batch_data])\n",
    "    address1 = np.array([address2onehot(x[0]) for x in input_addresses])\n",
    "    address2 = np.array([address2onehot(x[1]) for x in input_addresses])\n",
    "    \n",
    "    train_feed_dict = {address1_ph: address1,\n",
    "                       address2_ph: address2,\n",
    "                       y_target_ph: target_similarity,\n",
    "                       dropout_keep_prob_ph: dropout_keep_prob}\n",
    "\n",
    "    _, train_loss, train_acc = sess.run([train_op, batch_loss, batch_accuracy],\n",
    "                                        feed_dict=train_feed_dict)\n",
    "    # Save train loss and accuracy\n",
    "    train_loss_vec.append(train_loss)\n",
    "    train_acc_vec.append(train_acc)\n",
    "    # Print out statistics\n",
    "    if b%10==0:\n",
    "        print('Training Metrics, Batch {0}: Loss={1:.3f}, Accuracy={2:.3f}.'.format(b, train_loss, train_acc))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us test the algorithm on the test set of addresses."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Query Addresses: ['111 abbey ln', '271 doner cicle', '314 king avenue', 'tensorflow is fun']\n",
      "Model Found Matches: ['123 abbey ln', '217 donner cir', '217 donner cir', 'tensorflow is so fun']\n"
     ]
    }
   ],
   "source": [
    "# Calculate the nearest addresses for test inputs\n",
    "# First process the test_queries and test_references\n",
    "test_queries_ix = np.array([address2onehot(x) for x in test_queries])\n",
    "test_references_ix = np.array([address2onehot(x) for x in test_references])\n",
    "num_refs = test_references_ix.shape[0]\n",
    "best_fit_refs = []\n",
    "for query in test_queries_ix:\n",
    "    test_query = np.repeat(np.array([query]), num_refs, axis=0)\n",
    "    test_feed_dict = {address1_ph: test_query,\n",
    "                      address2_ph: test_references_ix,\n",
    "                      y_target_ph: target_similarity,\n",
    "                      dropout_keep_prob_ph: 1.0}\n",
    "    test_out = sess.run(text_snn, feed_dict=test_feed_dict)\n",
    "    best_fit = test_references[np.argmax(test_out)]\n",
    "    best_fit_refs.append(best_fit)\n",
    "\n",
    "print('Query Addresses: {}'.format(test_queries))\n",
    "print('Model Found Matches: {}'.format(best_fit_refs))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is great! The model generalizes to strings that aren't even addresses!!\n",
    "\n",
    "Now let us plot the loss and accuracy."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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uUXDRxZMpTBv3jyPfeYkN6tSWLduHVq2bInx48cDcPUUpk+fDgBYu3atY5vdbseIESO8jm6Ki4tzLB89evRSqlHgzJo1C+Hh4YUthpIPpKeno0aNGuqpFlOICDVq1LikL0iqUrBgPggPPvggkpOTXd51dNlllwFw7WiePXs2AJkZnZGR4aIUvPHnn39i9uzZePbZZz32FUWlcOTIEWRlZflNs2nTJjz++OPo0qVLUGTQPpaCRxVC8eZSr58qBQuXX365Y7lSpUouH9ypWbMmAODEiRMAJNyzZMkSAEBiYiJCQkJw4MABr/maI5Gss6fdRydZlcKRI0cupRr5wvr169G8eXO89NJLftNFRkYGTYbJkyejSZMmuHjxYtDKUBTFFVUKkPh/ly5d8M0337hstzbcXbt2BSDhIGbGmjVrkJyc7DW/MmVcu2pM78I609m9obOuFwVP4e+//wYAbN261W+6YFryb7/9Nk6cOIEffvghaGUoRY/SpUujffv2aNeuHTp06ODzDQMm8fHx+PTTT3PMt3v37o65RL44duwYWrdunSt5/22oUgDQq1cv/P3337j66qtdtlvdsNatW6N+/fo4c+YM/vrrLyxfvhwAMHr0aPTs2dPluB49erism+9SsnoA7qGmouYpmDLkpKAyMjK8LucnNpstKPkqRZMKFSpg586d2LVrF958880cv5AYqFJQAkOVgh8WLlyIypUr4+effwYRoXfv3gCAm266CV9++SUAYNiwYVizZg2aNWvmOO7NN9908Ra8KQXrSCXAu6fw3Xff4c0337ykOqxduxbdunXDyZMnPfbZbDb88ssvXjulTFlPnjzp8k0Jd6xyWxXbpWJ9TYi+MqRwqFq1Kogo33+5ITEx0THIIzk5Gbfddhs6dOiANm3aOMK3kydPxpEjR9C+fXs8//zzAMTLbNOmDdq1a+f4nC4ALFq0CF26dEHLli2xadOmgOXYuXMnbrjhBrRt2xZ33XWX417/+OOP0apVK7Rt2xb3338/AGDDhg1o37492rdvj+uuu85l/lKxwJwwVVx+HTt25LwSGhqa62Oys7Ndjgfg8jP3jxo1yrGNmfnEiRN8yy23MABetmwZMzM3b97ckWbhwoUu5bz88ssu+aampjqWDx06lOe6mHn079/fY9+4ceMYAI8bN85jX8OGDR3HHj582Gf+EyZMcKTb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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the loss and accuracy\n",
    "%matplotlib inline\n",
    "plt.plot(train_loss_vec, 'k-', lw=2, label='Batch Loss')\n",
    "plt.plot(train_acc_vec, 'r:', label='Batch Accuracy')\n",
    "plt.xlabel('Iterations')\n",
    "plt.ylabel('Accuracy and Loss')\n",
    "plt.title('Accuracy and Loss of Siamese RNN')\n",
    "plt.grid()\n",
    "plt.legend(loc='lower right')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
